home *** CD-ROM | disk | FTP | other *** search
- /* GRAPHIC LISP */
- /* Scritto nel 1991-94 da Zoia Andrea Michele */
- /* Via Pergola #1 Tirano (SO) Tel. 0342-704210 */
- /* file closfunc.c */
-
- #include "clos.h"
-
- void print_s_expr();
- int skip_spaces_tabs_nwl();
-
- int chw;
- char sbuf[MAX_ID_LENGHT+1];
- FILE *print_sx_fileout;
-
-
-
-
- void eval LF_PARAMS
- {
- /* la funzione eval ritorna SEMPRE un nodo FIX cioé un nodo che */
- /* verrà recuperato dal GC insieme a tutti i suoi legami */
- /* un nodo FIX risiede comunque nella lock_list e verrà,eventualmente, */
- /* successivamente rimosso con la funzione node_signal */
- /* Esempio (LIST (CONS 1 2) (GC) ) -> ( (1.2) T ) */
- /* se il cons (1.2) non venisse FIX-ato il GC successivo lo distruggerebbe*/
- /* */
- /* Gli environment locale (lenv) e speciale (genv) contengono i legami */
- /* dinamici dell'interprete */
- /* */
- /* Il nodo nin é la s-espressione da valutare e deve essere un nodo FIX*/
- /* o appartenere ad una lista con un CONS precedente FIX-ato */
- /* */
- /* NOTA: Questa condizione é assicurata SEMPRE(!!) dal fatto che una */
- /* s-espressione da valutare può provenire da 2 parti: */
- /* 1) immessa da tastiera e dunque è sicuramente bloccata dato che */
- /* é compsta da nodi appena allocati (si veda closyacc.y) */
- /* 2) prelevata da un risultato di EVAL e dato che il */
- /* nodo ritornato da EVAL é sempre FIX ciò assicura sempre */
- /* la condizione. */
- /* Questa condizione assicura che quando si chiama una EVAL un'eventuale*/
- /* GC non corrompe la lista di ingresso dato che é FIX o é attaccata ad un*/
- /* CONS FIX. Casomai la valutazione modifichi proprio questa lista */
- /* con ad.es */
- /* (SETF list '(SETF (CDR list) nil), (EVAL list) */
- /* (funzione AUTOMODIFICANTE abbastanza strana ... ) */
- /* allora il reperimento del CDR FIX-a la lista ((CDR list) nil) che */
- /* non verrà comunque distrutta da un eventuale GC, il FIX-amento della*/
- /* lista lo fa proprio EVAL alla fine. Cioé come ho detto all'inizio */
- /* EVAL ritorna proprio un nodo FIX. */
- /* Le funzioni automodificanti sono abbastanza strane e generano spesso*/
- /* risultati inattesi, non ho mai visto nessuno utilizzarle, ne tantomeno*/
- /* le utilizzo io, comunque dal punto di vista teorico non devono confondere*/
- /* l'interprete o fargli generare errori interni. */
- /* */
- /* DIFFERENZA TRA NODI LOCK e NODI FIX */
- /* i nodi LOCK vengono recuperati DA SOLI dal GC */
- /* i nodi FIX vengono recuperati insieme alla loro sottolista. */
- /* es: ( 1 . 2 ) se il cons é FIX allora il GC recupera tutta la lista */
- /* se il cons é LOCK allora il GC non recupera i numeri 1 e 2 */
-
-
- unsigned long magic=0x12345678L;
- /* valore cercato dalla funzione stack_backtrace in modo da trovare sullo*/
- /* stack tutte le chiamate alla eval e mostrarle all' utente in caso di*/
- /* errore, é un metodo bruto e dipendente dal sistema infatti la funzione*/
- /* stack_backtrace, che usa magic, non può essere Ansi-C */
-
- REGISTER_MOD n_type t=TYPE(nin);
-
- #ifdef _Windows
- /* rilascia la CPU a Windows dato che non é preemptivo */
- if(SelfPreemptive){
- WindowsReleaseCPU();
- }
- #endif
-
- if(t&NT_IS_CONS){
- /* il nodo nin é un cons: la parte sinistra é un nome? */
- if(IS_NAME(CONSLEFT(nin))){
- nout->node=CONSLEFT(nin);
- }else{
- /* si valuta la sua parte sinistra per vedere */
- /* se é un simbolo atomico. NB: LAMBDA ritorna un simbolo atomico */
- /* anonimo con attaccata una funzione in modo da rendere uniforme */
- /* e semplice questa parte di codice. */
- eval(CONSLEFT(nin),nout,genv,lenv,EVAL_SETF);
-
- /* se si valuta ad.es (10 20) -> ERRORE 10 non é una funzione! */
- if(!IS_NAME(nout->node))
- error(E_BADFUNC,ERR_TBLVL|ERR_MERROR|ERR_PNODE,&nout->node);
- }
- /* se si valuta ad.es (A 20) -> ERRORE A non ha un legame funzionale */
- if(!HAS_FUNCTION(nout->node))
- error(E_UNBOUNDFUNC,ERR_TBLVL|ERR_MERROR|ERR_PNODE,&nout->node);
-
- /* si chiama la funzione */
- apply_func(FUNCTION(nout->node),CONSRIGHT(nin),nout,genv,lenv,fl);
-
- /* apply_func blocca (FIX) il risultato nout */
- return;
-
- }
-
- if(t&NT_IS_NAME){
- /* Se nin e'un simbolo atomico ad.es 'A' */
-
- /* 1) controlla se ha un valore globale */
- if(t&NT_HAS_VALUE){
- nout->type=P_VALUE;
- nout->node=nin;
- node_lock(VALUE(nin));
- return;
- }
-
- /* 2) controlla se e' un nodo DEFVAR legame speciale libero */
- if(t&NT_HAS_BIND){
- /* lo cerca nell'environment speciale */
- if(find_in_alist(nin,nout,genv)){
- /* non lo ha trovato */
- /* si prende il valore di default */
- nout->type=P_VALUE;
- nout->node=nin;
- node_lock(VALUE(nin));
- return;
- }
- /* lo ha trovato e lo blocca */
- node_lock(CONSRIGHT(nout->node));
- return;
- }
-
- /* 3) é un legame locale */
- /* controlla se e' in local environment e se lo trova: OK */
- if(!find_in_alist(nin,nout,lenv)){
- /* lo ha trovato e lo blocca */
- node_lock(CONSRIGHT(nout->node));
- return;
- }
-
- /* altrimenti se eval e' chiamata da setf */
- /* ritorna il puntatore al valore globale (unbound) del nodo */
- if(fl==EVAL_SETF){
- nout->type=P_UNBOUNDVALUE; /* solo per SetF */
- nout->node=nin;
- return;
- }
- error(E_UNBOUND,ERR_TBLVL|ERR_MERROR|ERR_PNODE,&nin);
- }
-
- /* se e'un nodo-valore ritorna tutto il nodo */
- nout->type=P_ALLNODE;
- nout->node=nin;
- node_lock(nin);
- return;
- }
-
-
- void apply_func(func,nin,nout,genv,lenv,fl)
- node func;
- node nin;
- node_p *nout;
- node genv;
- node lenv;
- unsigned fl;
- {
- /* CAMPIONA LO STATO DI LOCK LIST, alla fine della valutazione lock-list*/
- /* verrà riportata alle condizioni quì memorizzate */
- node remalloc=node_getlastlock();
-
- /* BLOCCA GLI ENVIRONMENT in modo che un eventuale GC valutando */
- /* una funzione non li distrugga */
- node_lock(genv);
- node_lock(lenv);
-
- /* BLOCCA la funzione corrente dato che potrebbe essere unbound-ata */
- /* al suo interno es: (defun R() (defun R() 'y) 'x) */
- /* ""per curiosità"" la prima volta (r) torna X la seconda */
- /* (e le successive) (r) tornano Y) alcuni interpreti quì */
- /* falliscono miseramente. */
- node_lock(func);
-
- if(IS_TRACE(func)){
- sprintf(buf1,"Calling function: %s\n",string_get(NAME(CONSLEFT(nin)),buf2));
- lisp_print_string(buf1,stderr);
- lisp_print_string("Parameter list:",stderr);
- fprint_func(CONSRIGHT(nin),stderr);
- lisp_print_string("\nLocal environment:",stderr);
- fprint_func(lenv,stderr);
- lisp_print_string("\nSpecial environment:",stderr);
- fprint_func(genv,stderr);
- lisp_print_string("\nHit a key\n",stderr);
- cl_getch();
- }
- switch(GET_VTYPE(func)){
- case NT_SYSFUNC:
- (*SYSFUNC(func))(nin,nout,genv,lenv,fl);
- break;
- case NT_UFUNC:
- lambda_eval(func,eval_list(nin,genv,lenv),nout,genv,lenv,fl);
- break;
- case NT_MACRO:
- macro_eval(func,nin,nout,genv,lenv,fl);
- break;
- case NT_METHOD:
- method_eval(METHOD(func),eval_list(nin,genv,lenv),nout,genv,lenv,fl);
- break;
- case NT_ACCESSOR:
- accessor_eval(func,nin,nout,genv,lenv);
- break;
- default:
- /* se si lega una non-funzione ad un legame funzionale */
- /* si finisce quì .... */
- /* es: (SETF #'A 100) (A 12) */
- error(E_BADFUNC,ERR_TBLVL|ERR_MERROR|ERR_PNODE,&func);
- }
- if(IS_TRACE(func)){
- sprintf(buf1,"Function: %s has returned:",string_get(NAME(CONSLEFT(nin)),buf2));
- lisp_print_string(buf1,stderr);
- fprint_func(calc_pointer(nout),stderr);
- lisp_print_string("\nHit a key\n",stderr);
- cl_getch();
- }
- /* riporta lo stato della memoria al momento precedente alla chiamata */
- /* recuperando di fatto TUTTI i nodi allocati, LOCK-ati e FIX-ati */
- /* generati dalla funzione valutata */
- node_signal(remalloc);
-
- /* però bisogna salvare il risultato */
- /* si pensi a (LIST (CONS 1 2) (GC)) se il risultato di (CONS 1 2) */
- /* non é bloccato allora (GC) lo rimuove. */
- /* NB: si usa calc_pointer per bloccare il nodo effettivamente puntato */
- /* da nout */
- node_lock(nout->node);
-
- /* NB: calc_pointer non controlla i flags UNBOUND */
- if((nout->type&0xf0)!=0x30)
- node_lock(calc_pointer(nout));
-
- /* si noti che, operando in questo modo, ovunque io chiami una eval */
- /* ho la sicurezza che tutti i legami visibili sono preservati */
- /* da un eventuale GC dato che si bloccano gli environment. */
- /* Inoltre il risultato ottenuto é automaticamente preservato */
- }
-
-
- node eval_list(list,genv,lenv)
- node list;
- node genv;
- node lenv;
- {
- /* genera una lista contenente tutti gli elementi di list valutati */
-
- node retlist=NIL;
- node prev;
- node_p nout;
-
- while(IS_CONS(list)){
- eval(CONSLEFT(list),&nout,genv,lenv,EVAL_NORM);
- if(retlist==NIL){
- retlist=prev=node_make();
- }else{
- CONSRIGHT(prev)=node_make();
- prev=CONSRIGHT(prev);
- }
- TYPE(prev)|=NT_IS_CONS;
- CONSLEFT(prev)=calc_pointer(&nout);
- CONSRIGHT(prev)=NIL;
- list=CONSRIGHT(list);
- }
- return retlist;
- }
-
-
- /*=========== funzioni di stampa dei nodi ============================== */
-
- /* stampa il nodo n sullo stream f senza appendere newline */
- node fprint_func( n,f)
- node n;
- FILE *f;
- {
- print_sx_fileout=f;
- chw=0;
- print_s_expr(n,1);
- return n;
- }
-
-
- void print_s_expr( no, f)
- node no;
- int f;
- {
- node n;
-
- if(chw>60){ chw=0;lisp_print_string("\n",print_sx_fileout); }
-
- switch(GET_NTYPE(no)){
- case NT_IS_VALUE:
- switch(GET_VTYPE(no)){
- case NT_INTEGER:
- sprintf(sbuf,"%ld",INTEGER(no));
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=strlen(sbuf);
- return;
- case NT_REAL:
- sprintf(sbuf,"%15.15lf",REAL(no));
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=strlen(sbuf);
- return;
- case NT_RATIO:
- sprintf(sbuf,"%ld/%ld",RATIO_NUM(no),RATIO_DEN(no));
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=strlen(sbuf);
- return;
- case NT_STRING:
- sprintf(sbuf,"\"%s\"",string_get(STRING(no),buf1));
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=strlen(sbuf);
- return;
- case NT_CNAME:
- sprintf(sbuf,":");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=1;
- print_s_expr(CNAME(no),1);
- return;
- case NT_ENAME:
- sprintf(sbuf,"&");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=1;
- print_s_expr(ENAME(no),1);
- return;
- case NT_METHOD:
- sprintf(sbuf,"#<Method funcs:%ld>",(long)listlen_func(METHOD(no)));
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=strlen(sbuf);
- return;
- case NT_CLASS:
- sprintf(sbuf,"#<Class :");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=strlen(sbuf);
- print_s_expr(CLASS_INSTANCE(no),1);
- lisp_print_string(">",print_sx_fileout);
- chw++;
- return;
- case NT_SYSFUNC:
- sprintf(sbuf,"#<SysFunc %p>",SYSFUNC(no));
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=strlen(sbuf);
- return;
- case NT_STREAM:
- sprintf(sbuf,"#<Stream %p>",STREAM(no));
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=strlen(sbuf);
- return;
- case NT_ACCESSOR:
- sprintf(sbuf,"#<Accessor of class %s field %ld>",
- string_get(NAME(ACCESSOR_NAME(no)),buf1),ACCESSOR_FIELD(no));
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=strlen(sbuf);
- return;
- case NT_CHAR:
- sprintf(sbuf,"#\\%c",CHARACTER(no));
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=strlen(sbuf);
- return;
- case NT_MACRO:
- sprintf(sbuf,"#<Macro Lexical Closure par:");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=25;
- goto PrintUfunc;
- case NT_UFUNC:
- sprintf(sbuf,"#<Lexical Closure par:");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=19;
- PrintUfunc:
- print_s_expr(UFUNC_PAR(no),1);
-
- sprintf(sbuf," type:");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=6;
- print_s_expr(UFUNC_TYPE(no),1);
-
- sprintf(sbuf," opt:");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=5;
- print_s_expr(UFUNC_OPT(no),1);
-
- sprintf(sbuf," rest:");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=6;
- print_s_expr(UFUNC_REST(no),1);
-
- sprintf(sbuf," key:");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=5;
- print_s_expr(UFUNC_KEY(no),1);
-
- sprintf(sbuf," aux:");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=5;
- print_s_expr(UFUNC_AUX(no),1);
-
- sprintf(sbuf," sex:");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=5;
- print_s_expr(UFUNC_SEX(no),1);
-
- sprintf(sbuf," env:");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=5;
- print_s_expr(UFUNC_ENV(no),1);
-
- sprintf(sbuf,">");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=1;
- return;
-
- default:
- error(E_PRINT_BAD1,ERR_MINTERNAL|ERR_TNORM|ERR_PVOID,NULL);
- return;
- }
- case NT_IS_CONS:
- if(f){
- sprintf(sbuf,"(");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=1;
- }
- print_s_expr(CONSLEFT(no),1);
- if((n=CONSRIGHT(no))==NIL){
- sprintf(sbuf,")");
- lisp_print_string(sbuf,print_sx_fileout);
- chw+=1;
- return;
- }
- if(IS_CONS(n)){
- sprintf(sbuf," ");chw+=1;
- lisp_print_string(sbuf,print_sx_fileout);
- print_s_expr(n,0);
- return;
- }
- sprintf(sbuf," . ");chw+=3;
- lisp_print_string(sbuf,print_sx_fileout);
- print_s_expr(n,1);
- sprintf(sbuf,")");chw+=1;
- lisp_print_string(sbuf,print_sx_fileout);
- return;
-
- case NT_IS_NAME:
- if(HAS_NAME(no)){
- #ifdef LISPMEM_DEBUG
- sprintf(sbuf,"%s{this %p hash %lu next %p}"
- ,string_get(NAME(no),buf1),(node_s*)no,HASH(no),NEXT(no));
- #else
- sprintf(sbuf,"%s",string_get(NAME(no),buf1));
- chw+=strlen(sbuf);
- #endif
- lisp_print_string(sbuf,print_sx_fileout);
- return;
- }
- sprintf(sbuf,"#<anonymous node %p>",P(no));
- lisp_print_string(sbuf,print_sx_fileout);
- return;
- default:
- error(E_PRINT_BAD2,ERR_MINTERNAL|ERR_TNORM|ERR_PVOID,NULL);
- return;
- }
- }
-
-
-
-
-